import base64
import json
import pickle
from django.shortcuts import render
from django.views import View
from apps.goods.models import SKU
from django.http import JsonResponse
from django_redis import get_redis_connection
from apps.goods.models import SKU

# Create your views here.
"""
1.  京东的网址  登录用户可以实现购物车，未登录用户也可以实现购物车
    淘宝的网址  必须是登录用户才可以实现购物车

2.  登录用户数据保存在哪里？    服务器里        mysql/redis
    
    未登录用户数据保存在哪里    客户端         cookie
3.  保存哪些数据？？？   
    redis:
            user_id,sku_id(商品id),count(数量),selected(选中状态)
    cookie:
            sku_id,count,selected

################################### 编码数据 #####################################
cart_one = {
    '1': {'count': 10, 'selected': True},
    '2': {'count': 20, 'selected': False}
}

import pickle

byte_date = pickle.dumps(cart_one)

import base64
encode_data = base64.b64encode(byte_date)
#################################################################################

################################  解码数据  ######################################
decode_data = base64.b64decode(encode_data)

pickle.loads(decode_data)
#################################################################################
"""


class CartsView(View):
    def get(self, request):
        # 1. 验证用户是否登录
        user = request.user

        # 2. 登录状态去redis中获取数据
        if user.is_authenticated:
            redis_cli = get_redis_connection('carts')
            pipeline = redis_cli.pipeline()

            sku_id_count = redis_cli.hgetall(f'carts_{user.id}')  # type: dict
            selected_bytes_ids = redis_cli.smembers(f'selected_{user.id}')
            selected_ids = [int(selected_id) for selected_id in selected_bytes_ids]

            # 将redis数据转换为和cookie一样
            carts = dict()
            for sku_id, count in sku_id_count.items():
                carts[int(sku_id)] = {'count': int(count), 'selected': int(sku_id) in selected_ids}
        # 未登录状态去cookie中获取数据
        else:
            cookie_carts = request.COOKIES.get('carts')

            if cookie_carts:
                bytes_carts = base64.b64decode(cookie_carts)
                carts = pickle.loads(bytes_carts)
            else:
                carts = dict()

        # 4. 根据商品id查询商品信息
        sku_ids = carts.keys()
        skus = SKU.objects.filter(id__in=sku_ids)
        # 5. 将对象数据转换为字典数据
        data = list()
        for sku in skus:
            data.append({
                'id': sku.id,
                'name': sku.name,
                'price': sku.price,
                'default_image_url': sku.default_image.url,
                'selected': carts[sku.id]['selected'],
                'count': carts[sku.id]['count'],
                'amount': sku.price * carts[sku.id]['count']
            })

        # 6. 返回响应
        return JsonResponse({'code': 0, 'errmsg': 'ok', 'cart_skus': data})

    def post(self, request):
        # 1. 接收数据
        sku_id = json.loads(request.body.decode()).get('sku_id')
        count = json.loads(request.body.decode()).get('count')
        # 2。验证数据
        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return JsonResponse({'code': 400, 'errmsg': '参数错误'})

        try:
            count = int(count)
        except Exception:
            count = 1
        # 3. 判断用户的登录状态
        # request.user 如果是登录用户，就是关联User的模型数据
        # is_authenticated = True   认证用户
        # 如果不是登录用户，就是匿名用户
        # 匿名用户的 is_authenticated = False
        user = request.user
        if user.is_authenticated:
            # 4.  登录用户保存redis
            #   4.1  连接redis
            redis_cli = get_redis_connection('carts')
            pipeline = redis_cli.pipeline()
            # 判断该商品是否已经添加到购物车
            #   4.2  操作hash
            # hincrby  会进行累加操作
            pipeline.hincrby(f'carts_{user.id}', sku_id, count)
            #   4.3  操作set
            # 默认就是选中
            pipeline.sadd(f'selected_{user.id}', sku_id)
            pipeline.execute()
            #   4.4  返回响应
            return JsonResponse({'code': 0, 'errmsg': 'ok'})
        else:
            # 5. 未登录用户保存cookie
            #     5.0 先读取 cookie 数据
            #     判断新增的商品  有没有在购物车里
            cookie_carts = request.COOKIES.get('carts')
            if cookie_carts:
                bytes_data = base64.b64decode(cookie_carts)
                data = pickle.loads(bytes_data)
            else:
                #     5.1 先有cookie字典
                data = dict()
            if sku_id not in data:
                data[sku_id] = {'count': count, 'selected': True}
            else:
                data[sku_id]['count'] += count
            #     5.2 字典转换为bytes
            bytes_data = pickle.dumps(data)
            #     5.3 bytes 类型数据 base64编码
            base64_data = base64.b64encode(bytes_data)
            #     5.4 设置cookie
            response = JsonResponse({'code': 0, 'errmsg': 'ok'})
            #  base64_data.decode() 的作用是  将bytes 类型转换为 str
            # 因为value的数据是str数据
            response.set_cookie('carts', base64_data.decode(), max_age=3600 * 24)
            #     5.5 返回响应
            return response

    def put(self, request):
        body_params = json.loads(request.body.decode())
        sku_id = body_params.get('sku_id')
        count = body_params.get('count')
        selected = body_params.get('selected')

        if not all([sku_id, count]):
            return JsonResponse({'code': 400, 'errmsg': '缺少必填参数'})

        if not isinstance(selected, bool):
            return JsonResponse({'code': 400, 'errmsg': '参数selected有误'})

        try:
            count = int(count)
        except Exception:
            return JsonResponse({'code': 400, 'errmsg': '参数count有误'})

        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return JsonResponse({'code': 400, 'errmsg': '该商品不存在'})

        user = request.user

        if user.is_authenticated:
            redis_cli = get_redis_connection('carts')
            pipeline = redis_cli.pipeline()

            pipeline.hset(f'carts_{user.id}', sku_id, count)

            if selected:
                pipeline.sadd(f'selected_{user.id}', sku_id)
            else:
                pipeline.srem(f'selected_{user.id}', sku_id)

            pipeline.execute()

            cart_sku = {
                'id': sku_id,
                'count': count,
                'selected': selected,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price,
                'amount': sku.price * count
            }

            return JsonResponse({'code': 0, 'errmsg': 'ok', 'cart_sku': cart_sku})
        else:
            cookie_carts = request.COOKIES.get('carts')

            if cookie_carts:
                carts = pickle.loads(base64.b64decode(cookie_carts))
            else:
                carts = dict()

            if sku_id in carts:
                carts[sku_id] = {
                    'count': count,
                    'selected': selected
                }

            bytes_carts = pickle.dumps(carts)
            base64_carts = base64.b64encode(bytes_carts)

            response = JsonResponse({'code': 0, 'errmsg': 'ok'})

            response.set_cookie('carts', base64_carts.decode(), max_age=3600 * 24)

            return response

    def delete(self, request):
        sku_id = json.loads(request.body.decode()).get('sku_id')

        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return JsonResponse({'code': 0, 'errmsg': '参数错误'})

        user = request.user

        if user.is_authenticated:
            redis_cli = get_redis_connection('carts')
            redis_cli.hdel(f'carts_{user.id}', sku_id)
            redis_cli.srem(f'selected_{user.id}', sku_id)

            return JsonResponse({'code': 0, 'errmsg': 'ok'})
        else:
            cookie_carts = request.COOKIES.get('carts')

            if cookie_carts:
                raw_carts = pickle.loads(base64.b64decode(cookie_carts))

                if raw_carts:
                    try:
                        del raw_carts[sku_id]
                    except Exception:
                        return JsonResponse({'code': 0, 'errmsg': '参数错误'})

                carts = base64.b64encode(pickle.dumps(raw_carts))
            else:
                carts = cookie_carts

            response = JsonResponse({'code': 0, 'errmsg': 'ok'})

            response.set_cookie('carts', carts.decode(), max_age=3600 * 24)

            return response


class CartsSelectedView(View):
    def put(self, request):
        selected = json.loads(request.body.decode()).get('selected', True)

        if not isinstance(selected, bool):
            return JsonResponse({'code': 400, 'errmsg': 'selected参数错误'})

        user = request.user

        if user.is_authenticated:
            redis_cli = get_redis_connection('carts')
            selected_id_count = redis_cli.hgetall(f'carts_{user.id}')  # type: dict
            sku_ids = selected_id_count.keys()

            if selected:
                redis_cli.sadd(f'selected_{user.id}', *sku_ids)
            else:
                redis_cli.srem(f'selected_{user.id}', *sku_ids)

            return JsonResponse({'code': 0, 'errmsg': 'ok'})

        else:
            cookie_carts = request.COOKIES.get('carts')

            if cookie_carts:
                carts = pickle.loads(base64.b64decode(cookie_carts))
                sku_ids = carts.keys()

                if selected:
                    for sku_id in sku_ids:
                        carts[sku_id]['selected'] = True
                else:
                    for sku_id in sku_ids:
                        carts[sku_id]['selected'] = False

            else:
                carts = dict()

            data = base64.b64encode(pickle.dumps(carts))

            response = JsonResponse({'code': 0, 'errmsg': 'ok'})

            response.set_cookie('carts', data.decode(), max_age=3600 * 24)

            return response
